package prog.model;



import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Enumeration;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML.Attribute;
import javax.swing.text.html.HTML.Tag;
import javax.swing.text.html.HTMLEditorKit.ParserCallback;
import javax.swing.text.html.parser.ParserDelegator;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author MrKhoai
 */
public class HtmlPage extends Data {
    private URL url = null;
    private URL home = null;
    private String charset = null;
    private ArrayList<Data> srcList = null;
    private StringBuffer page = null;
    private ArrayList<MyTag> impTag = null;
    private int lvLimit = 0;
    private Project project = null;
    private boolean DEBUG = true;

    public HtmlPage(String spec) throws MalformedURLException {
        url = new URL(spec);
        home = new URL(url.getProtocol() + "://" + url.getHost() + '/');
        srcList = new ArrayList<Data>();
        impTag = new ArrayList<MyTag>();
        charset = "UTF-8";
    }

    public Reader getPage() throws IOException, InterruptedException {
        if(page == null) {
            Socket socket = new Socket();
            InetSocketAddress iAddr = new InetSocketAddress(url.getHost(), 80);
            socket.connect(iAddr);
            BufferedWriter writer = new BufferedWriter(
                                 new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
            BufferedInputStream _reader = new BufferedInputStream(socket.getInputStream());
            writer.write("GET " + url + " HTTP/1.0\r\n");
            writer.write("Accept: */*\r\n\r\n");
            
            writer.flush();
            page = new StringBuffer();
            readPageToBuffer(_reader);
            writer.close();
        }
        
        return new StringReader(page.toString());
    }

    public void parse() throws IOException, InterruptedException {
        Reader _reader = getPage();
        ParserDelegator parserDelegator = new ParserDelegator();
        MyHtmlParserCallBack parserCallback = new MyHtmlParserCallBack();
        parserDelegator.parse(_reader, parserCallback, true);
    }

    public void download(String dst) throws IOException, InterruptedException {
        
        if(lvLimit >= 0) {//Cần sửa chỗ này
            parse();
            editImpTag();
            srcList = DataFilter.dataFiltering(project, srcList);
            editPage();
            project.putToStack(srcList);
            writeToFile(dst);
        }
    }

    public boolean sureDownload() {return true;}

//    public void downloadResource(String dst) throws IOException {
//        for(Data src : srcList) {
//            src.writeToFile(dst);
//        }
//    }

    public void readPageToBuffer(InputStream in) throws IOException, InterruptedException {
        BufferedInputStream _reader = (BufferedInputStream)in;
        byte[] bytes = new byte[5120];
        int nbyte = _reader.read(bytes);
        String line = new String(bytes, 0, nbyte, charset);
        int startIndex = line.indexOf("\r\n\r\n");
        String sub = line.substring(startIndex);
        int i = sub.indexOf("charset");
        int j = -1;
        if(i != -1) {
            i +=8;
            j = sub.indexOf('"', i);
            charset = sub.substring(i, j);//System.out.println(url);System.out.println(charset);
        }
        
        line = new String(bytes, 0, nbyte, charset);
        line = line.substring(startIndex);
        page.append(line);//System.out.println(line);
        nbyte = _reader.read(bytes);
        while(nbyte != -1) {
            line = new String(bytes, 0, nbyte, charset);
            page.append(line);//System.out.println(line);
            nbyte = _reader.read(bytes);
        }
        _reader.close();
    }

    public void editPage() {
        int nchar = 0;
        for(MyTag tag : impTag) {
            int startPos = nchar + tag.getPos();
            int endPos = startPos;
            while(page.charAt(endPos) != '>') {
                endPos++;
            }

            nchar += tag.lenghtTag() - (++endPos - startPos);
            page.delete(startPos, endPos);
            page.insert(startPos, tag.toString());
        }
    }

    public void editImpTag() throws MalformedURLException {
        
        for(MyTag tag : impTag) {
            if(tag.getName().equals(Tag.A.toString())) {
                MyAttribute att = tag.getAttribute(Attribute.HREF.toString());
                if(att == null)
                    continue;
                String _url = att.getValue();
                HtmlPage href = null;
                String _href = null;
                if(_url.startsWith("http://")) {
                    
                    _href = _url.replaceFirst("http://", "");
                    String[] s = _href.split("/");
                    if(_href.endsWith("/"))
                        _href = "../" + s[0] + '/' + s[s.length-1] + ".html";
                    else
                        _href = "../" + s[0] + '/' + s[s.length-1];
                }
                else
                if(_url.startsWith("/")) {
                    _url = _url.replaceFirst("/", "");
                    _href = _url;
                    String[] s = _href.split("/");
                    if(_href.endsWith("/"))
                        _href = s[s.length-1] + ".html";
                    else
                        _href = s[s.length-1];
                    _url = home.toString() + _url;

                }
                else {
                    _href = _url;
                    String[] s = _href.split("/");
                    if(_href.endsWith("/"))
                        _href = s[s.length-1] + ".html";
                    else
                        _href = s[s.length-1];
                    _url = home.toString() + _url;

                }
                href = new HtmlPage(_url);
                href.setLvLimit(lvLimit-1);
                href.putToProject(project);
                srcList.add(href);
                _href = _href.replace('?', '@');
                _href = _href.replace('\\', '@');
                _href = _href.replace(':', '@');
                _href = _href.replace('*', '@');
                _href = _href.replace('<', '@');
                _href = _href.replace('>', '@');
                _href = _href.replace('|', '@');
                tag.updateAttribute(Attribute.HREF.toString(), _href);
            }

            if(tag.getName().equals(Tag.IMG.toString())) {
                MyAttribute att = tag.getAttribute(Attribute.SRC.toString());//System.out.println(att.toString());
                if(att == null)
                    continue;
                String _url = att.getValue();
                Resource src = null;
                String _href = null;
                if(_url.startsWith("http://")) {
                    _href = _url;
                    _href = _href.replaceFirst("http://", "../");

                }
                else
                if(_url.startsWith("/")) {
                    _url = _url.replaceFirst("/", "");
                    _href = _url;
                    _url = home.toString() + _url;

                }
                else {
                    _href = _url;
                    _url = home.toString() + _url;

                }
                src = new Resource(_url);
                srcList.add(src);
                _href = _href.replace('?', '@');
                _href = _href.replace('\\', '@');
                _href = _href.replace(':', '@');
                _href = _href.replace('*', '@');
                _href = _href.replace('<', '@');
                _href = _href.replace('>', '@');
                _href = _href.replace('|', '@');
                tag.updateAttribute(Attribute.SRC.toString(), _href);
            }

            if(tag.getName().equals(Tag.LINK.toString())) {
                MyAttribute att = tag.getAttribute(Attribute.HREF.toString());//System.out.println(att.toString());
                if(att == null)
                    continue;
                String _url = att.getValue();
                Resource src = null;
                String _href = null;
                if(_url.startsWith("http://")) {
                    _href = _url;
                    _href = _href.replaceFirst("http://", "../");

                }
                else
                if(_url.startsWith("/")) {
                    _url = _url.replaceFirst("/", "");
                    _href = _url;
                    _url = home.toString() + _url;

                }
                else {
                    _href = _url;
                    _url = home.toString() + _url;

                }
                src = new Resource(_url);
                srcList.add(src);
                _href = _href.replace('?', '@');
                _href = _href.replace('\\', '@');
                _href = _href.replace(':', '@');
                _href = _href.replace('*', '@');
                _href = _href.replace('<', '@');
                _href = _href.replace('>', '@');
                _href = _href.replace('|', '@');
                tag.updateAttribute(Attribute.HREF.toString(), _href);
            }

            if(tag.getName().equals(Tag.SCRIPT.toString())) {
                MyAttribute att = tag.getAttribute(Attribute.SRC.toString());//System.out.println(att.toString());
                if(att == null)
                    continue;
                String _url = att.getValue();
                Resource src = null;
                String _href = null;
                if(_url.startsWith("http://")) {
                    _href = _url;
                    _href = _href.replaceFirst("http://", "../");

                }
                else
                if(_url.startsWith("/")) {
                    _url = _url.replaceFirst("/", "");
                    _href = _url;
                    _url = home.toString() + _url;

                }
                else {
                    _href = _url;
                    _url = home.toString() + _url;

                }
                src = new Resource(_url);
                srcList.add(src);
                _href = _href.replace('?', '@');
                _href = _href.replace('\\', '@');
                _href = _href.replace(':', '@');
                _href = _href.replace('*', '@');
                _href = _href.replace('<', '@');
                _href = _href.replace('>', '@');
                _href = _href.replace('|', '@');
                tag.updateAttribute(Attribute.SRC.toString(), _href);
            }
        }
    }

    public void setLvLimit(int lv) {
        lvLimit = lv;
    }

    public int getLvLimit() {
        return lvLimit;
    }

    public String getURL() {
        return url.toString();
    }

    public void putToProject(Project pj) {
        project = pj;
    }

    public String toString() {
        return (url.toString() + " " + lvLimit);
    }

    public void editSubTag() {

    }

    public void writeToFile(String dst) throws IOException {
        
        if(!dst.endsWith("/")) {
            dst += '/';
        }

        String host = url.getHost();
        String path = url.getFile();
        path = path.replace('?', '@');
        path = path.replace('\\', '@');
        path = path.replace(':', '@');
        path = path.replace('*', '@');
        path = path.replace('<', '@');
        path = path.replace('>', '@');
        path = path.replace('|', '@');
        int index = path.lastIndexOf('/');
        String name = null;
        if(index != -1) {
            String s = path.substring(0, index);
            File ff = new File(dst + host + s);
            if(!ff.exists()) {
                ff.mkdirs();
            }
            if(index == 0)
                name = host + ".html";
            else {
                if(path.endsWith("/")) {
                    String[] pname = path.split("/");
                    name = pname[pname.length-1] + ".html";
                }
                else
                    name = path.substring(index + 1);
            }
        }
        else {
            if(path.equals("")) {
                File ff = new File(dst + host);
                if(!ff.exists())
                    ff.mkdirs();
            }
            name = host + ".html";
        }
        File out = new File(dst + host + '/' + name);

        if(!out.exists()) {
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(out), charset));
            writer.write(page.toString());
            writer.close();
        }
    }
    
    public void analyzePage() {
        
    }

    public void addResource(String spec) {

    }

    public void addSubLink(String url) {
        
    }

    public void addImpTag(MyTag tag) {
        if(tag != null)
            impTag.add(tag);
    }

    public MyTag getImpTag(int index) {
        if(index > -1)
            return impTag.get(index);
        return null;
    }

    // <editor-fold defaultstate="collapsed" desc="class MyHtmlParserCallBack">
    private class MyHtmlParserCallBack extends ParserCallback {
        private ArrayList<MyTag> tagList;

        public MyHtmlParserCallBack() {}

        @Override
        public void handleStartTag(Tag t, MutableAttributeSet a, int pos) {
            if(t == Tag.A) {
                String tagName = t.toString();
                Enumeration e = a.getAttributeNames();
                MyAttributeSet set = new MyAttributeSet();
                while(e.hasMoreElements()) {
                    Object name = e.nextElement();
                    Object value = a.getAttribute(name);//System.out.println(value);
                    set.addAttribute(name.toString(), value.toString());
                }
                MyTag tag = new MyTag(tagName, set, pos);
                addImpTag(tag);
            }

            if(t == Tag.SCRIPT) {
                String tagName = t.toString();
                Enumeration e = a.getAttributeNames();
                MyAttributeSet set = new MyAttributeSet();
                while(e.hasMoreElements()) {
                    Object name = e.nextElement();
                    Object value = a.getAttribute(name);//System.out.println(value);
                    set.addAttribute(name.toString(), value.toString());
                }
                MyTag tag = new MyTag(tagName, set, pos);
                addImpTag(tag);
            }
        }

        @Override
        public void handleEndTag(Tag t, int pos) {
            //System.out.println(t);
        }

        @Override
        public void handleSimpleTag(Tag t, MutableAttributeSet a, int pos) {
            if(t == Tag.IMG) {
                String tagName = t.toString();
                Enumeration e = a.getAttributeNames();
                MyAttributeSet set = new MyAttributeSet();
                while(e.hasMoreElements()) {
                    Object name = e.nextElement();
                    Object value = a.getAttribute(name);
                    set.addAttribute(name.toString(), value.toString());
                }
                MyTag tag = new MyTag(tagName, set, pos);
                addImpTag(tag);
            }

            if(t == Tag.LINK) {
                String tagName = t.toString();
                Enumeration e = a.getAttributeNames();
                MyAttributeSet set = new MyAttributeSet();
                while(e.hasMoreElements()) {
                    Object name = e.nextElement();
                    Object value = a.getAttribute(name);
                    set.addAttribute(name.toString(), value.toString());
                }
                MyTag tag = new MyTag(tagName, set, pos);
                addImpTag(tag);
            }
        }

        @Override
        public void handleText(char[] data, int pos) {
            //System.out.println(data);
        }

        @Override
        public void handleComment(char[] data, int pos) {
            //System.out.println(data);
        }

        @Override
        public void handleEndOfLineString(String eol) {

        }
    }
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="class MyTag">
    private class MyTag extends Tag {
        public MyTag() {}

        public MyTag(String name, MyAttributeSet atts, int pos) {
            this.tagName = name;
            this.atts = atts;
            this.pos = pos;
        }
        private String tagName;
        public void setName(String name) {
            this.tagName = name;
        }

        public String getName() {
            return this.tagName;
        }

        private MyAttributeSet atts;
        public void setAttributes(MyAttributeSet atts) {
            this.atts = atts;
        }

        private int pos;
        public void setPos(int pos) {
            this.pos = pos;
        }

        public int getPos() {
            return this.pos;
        }

        public int lenghtTag() {
            int leng;
            leng = tagName.length() + 2;

            for(int i = 0; i < atts.getCount(); i++) {
                leng += atts.getAttribute(i).getName().length() +
                        atts.getAttribute(i).getValue().length() +
                        4;
            }
            return leng;
        }

        public MyAttribute getAttribute(String attName) {
            String s;
            for(int i = 0; i < atts.getCount(); i++) {
                s = atts.getAttribute(i).getName();
                if(s.equals(attName)) {
                    return atts.getAttribute(i);
                }
            }
            return null;
        }

        public void updateAttribute(String attName, String value) {
            String s;
            for(int i = 0; i < atts.getCount(); i++) {
                s = atts.getAttribute(i).getName();
                if(s.equals(attName)) {
                    atts.getAttribute(i).setValue(value);
                    break;
                }
            }
        }

        @Override
        public String toString() {
            StringBuilder buffer = new StringBuilder();
            buffer.append('<');
            buffer.append(tagName);

            for(int i = 0; i < atts.getCount(); i++) {
                buffer.append(' ');
                buffer.append(atts.getAttribute(i).toString());
            }
            buffer.append('>');
            return buffer.toString();
        }
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="class MyAttribute">
    private class MyAttribute {
        private String att;
        public void setAttribute(String att) {
            this.att = att;
        }

        public String getName() {
            return this.att;
        }

        private String value;
        public void setValue(String value) {
            this.value = value;
        }

        public String getValue() {
            return this.value;
        }

        @Override
        public String toString() {
            StringBuilder buffer = new StringBuilder();
            buffer.append(att);
            buffer.append('=');
            buffer.append('"');
            buffer.append(value);
            buffer.append('"');

            return buffer.toString();
        }
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="class MyAttributeSet">
    private class MyAttributeSet {
        private ArrayList<MyAttribute> set;

        public MyAttributeSet() {
            set = new ArrayList<MyAttribute>();
        }

        public MyAttributeSet(ArrayList<MyAttribute> set) {
            this.set = set;
        }

        public void addAttribute(String name, String value) {
            MyAttribute att = new MyAttribute();
            att.setAttribute(name);
            att.setValue(value);
            set.add(att);
        }

        public MyAttribute getAttribute(int index) {
            return set.get(index);
        }

        public int getCount() {
            return set.size();
        }
    }
    // </editor-fold>
}
